﻿
// Mike ( lutinore@hotmail.fr ) - May 2007 - RawInput.NET.dll - Win32.cs

using System;
using System.Security;
using System.Runtime.InteropServices;

namespace Touchless.Multitouch.Devices.Native
{
    [Flags]
    internal enum PenStatus : byte
    {
        PenTipDown = 0x01,
        SideSwitchDown = 0x02,
        Inverted = 0x04,
        EraserDown = 0x08,
        Reserved = 0x18,
        InRange = 0x20,
        ControlData = 0x40,
        Sync = 0x80
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct PEN_DATA
    {
        public byte ReportID;
        public PenStatus Status;
        public ushort X;
        public ushort Y;
        public ushort Pressure;
        public byte XTilt;
        public byte YTilt;
        public ushort Firmware;
        public int Data;

        public override string ToString()
        {
            return string.Format("Report ID: {0}, Status: {1}, X-Y: {2}x{3}, Pressure: {4}, Tilt X-Y: {5}x{6}, Firmware: {7}, Data: {8}",
                                 ReportID, Status, X, Y, Pressure, XTilt, YTilt, Firmware, Data);
        }
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct RAWINPUTDEVICELIST
    {
        public IntPtr hDevice;
        public uint dwType;
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct RID_DEVICE_INFO_MOUSE
    {
        public uint dwId;
        public uint dwNumberOfButtons;
        public uint dwSampleRate;
        public int fHasHorizontalWheel; // Vista.
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct RID_DEVICE_INFO_KEYBOARD
    {
        public uint dwType;
        public uint dwSubType;
        public uint dwKeyboardMode;
        public uint dwNumberOfFunctionKeys;
        public uint dwNumberOfIndicators;
        public uint dwNumberOfKeysTotal;
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct RID_DEVICE_INFO_HID
    {
        public uint dwVendorId;
        public uint dwProductId;
        public uint dwVersionNumber;
        public ushort usUsagePage;
        public ushort usUsage;
    }

    [StructLayout(LayoutKind.Explicit)]
    internal struct RID_DEVICE_INFO
    {
        // Fields
        [FieldOffset(0)]
        public uint cbSize;
        [FieldOffset(4)]
        public uint dwType;
        [FieldOffset(8)]
        public RID_DEVICE_INFO_HID hid;
        [FieldOffset(8)]
        public RID_DEVICE_INFO_KEYBOARD keyboard;
        [FieldOffset(8)]
        public RID_DEVICE_INFO_MOUSE mouse;
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct RAWINPUTDEVICE
    {
        public ushort usUsagePage;
        public ushort usUsage;
        public uint dwFlags;
        public IntPtr hwndTarget;
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct RAWINPUTHEADER
    {
        public uint dwType;
        public uint dwSize;
        public IntPtr hDevice;
        public IntPtr wParam;
    }

    [StructLayout(LayoutKind.Explicit)]
    internal struct RAWMOUSE
    {
        [FieldOffset(0)]
        public ushort usFlags;
        [FieldOffset(4)] // Alignment.
        public uint ulButtons;
        [FieldOffset(4)] // Union.
        public ushort usButtonFlags;
        [FieldOffset(6)]
        public ushort usButtonData;
        [FieldOffset(8)]
        public uint ulRawButtons;
        [FieldOffset(12)]
        public int lLastX;
        [FieldOffset(16)]
        public int lLastY;
        [FieldOffset(20)]
        public uint ulExtraInformation;
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct RAWKEYBOARD
    {
        public ushort MakeCode;
        public ushort Flags;
        public ushort Reserved;
        public ushort VKey;
        public uint Message;
        public uint ExtraInformation;
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct RAWHID
    {
        public uint dwSizeHid;
        public uint dwCount;
        public byte bRawData; // fixed byte bRawData[ 1 ];
    }

    internal interface IRAWINPUT
    {
        RAWINPUTHEADER Header { get; set; }
        RAWMOUSE Mouse { get; set; }
        RAWKEYBOARD Keyboard { get; set; }
        RAWHID Hid { get; set; }
    }

    [StructLayout(LayoutKind.Explicit)]
    internal struct RAWINPUT32 : IRAWINPUT
    {
        [FieldOffset(0)]
        public RAWINPUTHEADER header;
        [FieldOffset(16)]
        public RAWMOUSE mouse;
        [FieldOffset(16)] // Union.
        public RAWKEYBOARD keyboard;
        [FieldOffset(16)] // Union.
        public RAWHID hid;

        public RAWINPUTHEADER Header
        {
            get { return header; }
            set { header = value; }
        }

        public RAWMOUSE Mouse
        {
            get { return mouse; }
            set { mouse = value; }
        }

        public RAWKEYBOARD Keyboard
        {
            get { return keyboard; }
            set { keyboard = value; }
        }

        public RAWHID Hid
        {
            get { return hid; }
            set { hid = value; }
        }
    }

    [StructLayout(LayoutKind.Explicit)]
    internal struct RAWINPUT64 : IRAWINPUT
    {
        [FieldOffset(0)]
        public RAWINPUTHEADER header;
        [FieldOffset(24)]
        public RAWMOUSE mouse;
        [FieldOffset(24)] // Union.
        public RAWKEYBOARD keyboard;
        [FieldOffset(24)] // Union.
        public RAWHID hid;

        public RAWINPUTHEADER Header
        {
            get { return header; }
            set { header = value; }
        }

        public RAWMOUSE Mouse
        {
            get { return mouse; }
            set { mouse = value; }
        }

        public RAWKEYBOARD Keyboard
        {
            get { return keyboard; }
            set { keyboard = value; }
        }

        public RAWHID Hid
        {
            get { return hid; }
            set { hid = value; }
        }
    }

    [SuppressUnmanagedCodeSecurity]
    internal static class Win32
    {
        public const int HWND_MESSAGE = -3;
        public const int WM_INPUT = 0x00FF;

        public const int RIM_TYPEMOUSE = 0;
        public const int RIM_TYPEKEYBOARD = 1;
        public const int RIM_TYPEHID = 2;

        //public const int RIDI_PREPARSEDDATA    = 0x20000005;
        public const int RIDI_DEVICENAME = 0x20000007;
        public const int RIDI_DEVICEINFO = 0x2000000b;

        public const int RIDEV_REMOVE = 0x00000001;
        //public const int RIDEV_EXCLUDE      = 0x00000010;
        //public const int RIDEV_PAGEONLY     = 0x00000020;
        //public const int RIDEV_NOLEGACY     = 0x00000030;
        //public const int RIDEV_INPUTSINK    = 0x00000100;
        //public const int RIDEV_CAPTUREMOUSE = 0x00000200;
        //public const int RIDEV_NOHOTKEYS    = 0x00000200;
        //public const int RIDEV_APPKEYS      = 0x00000400;
        //public const int RIDEV_EXINPUTSINK  = 0x00001000;
        //public const int RIDEV_DEVNOTIFY    = 0x00002000;

        //public const int RIM_INPUT      = 0;
        public const int RIM_INPUTSINK = 1;

        public const int RID_INPUT = 0x10000003;
        public const int RID_HEADER = 0x10000005;

        //public const ushort GENERIC_DESKTOP_PAGE    = 0x01;
        //public const ushort MOUSE_USAGE             = 0x02;
        //public const ushort KEYBOARD_USAGE          = 0x06;

        public const int RI_MOUSE_WHEEL = 0x0400;

        public static readonly uint SIZEOF_RAWINPUTDEVICELIST =
            (uint)Marshal.SizeOf(typeof(RAWINPUTDEVICELIST));
        public static readonly uint SIZEOF_RID_DEVICE_INFO =
            (uint)Marshal.SizeOf(typeof(RID_DEVICE_INFO));
        public static readonly uint SIZEOF_RAWINPUTDEVICE =
            (uint)Marshal.SizeOf(typeof(RAWINPUTDEVICE));
        public static readonly uint SIZEOF_RAWINPUTHEADER =
            (uint)Marshal.SizeOf(typeof(RAWINPUTHEADER));
        public static readonly uint SIZEOF_RAWINPUT64 =
            (uint)Marshal.SizeOf(typeof(RAWINPUT64));
        public static readonly uint SIZEOF_RAWINPUT32 =
            (uint)Marshal.SizeOf(typeof(RAWINPUT32));

        [SuppressUnmanagedCodeSecurity, SecurityCritical, DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern uint GetRawInputDeviceList([In, Out] RAWINPUTDEVICELIST[] ridl, [In, Out] ref uint numDevices, uint sizeInBytes);

        [SecurityCritical, SuppressUnmanagedCodeSecurity, DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern uint GetRawInputDeviceInfo(IntPtr hDevice, uint command, [In] ref RID_DEVICE_INFO ridInfo, ref uint sizeInBytes);

        [SecurityCritical, SuppressUnmanagedCodeSecurity, DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern uint GetRawInputDeviceInfo(IntPtr hDevice, uint command, [In] IntPtr ridInfo, ref uint sizeInBytes);


        [DllImport("user32.dll", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool RegisterRawInputDevices
            (
            IntPtr pRawInputDevices, // [ In ] RAWINPUTDEVICE[ ]
            uint uiNumDevices,
            uint cbSize
            );

        [DllImport("user32.dll", SetLastError = true)]
        public static extern uint GetRegisteredRawInputDevices
            (
            IntPtr pRawInputDevices, // [ In, Out ] RAWINPUTDEVICE[ ]
            ref uint puiNumDevices,
            uint cbSize
            );

        [DllImport("user32.dll")]
        public static extern uint GetRawInputData
            (
            IntPtr hRawInput,
            uint uiCommand,
            IntPtr pData, // [ In, Out ] byte[ ] // ref RAWINPUTHEADER
            ref uint pcbSize,
            uint cbSizeHeader
            );

        [DllImport("user32.dll")]
        public static extern uint GetRawInputData
            (
            IntPtr hRawInput,
            uint uiCommand,
            [Out] out RAWINPUT32 input,
            ref uint pcbSize,
            uint cbSizeHeader
            );

        [DllImport("user32.dll")]
        public static extern uint GetRawInputData
            (
            IntPtr hRawInput,
            uint uiCommand,
            [Out] out RAWINPUT64 input,
            ref uint pcbSize,
            uint cbSizeHeader
            );

        [StructLayout(LayoutKind.Sequential)]
        public class POINT
        {
            public int x;
            public int y;
            public POINT()
            {
            }

            public POINT(int x, int y)
            {
                this.x = x;
                this.y = y;
            }
        }

        [DllImport("user32.dll")]
        public static extern uint SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int x, int y, int nWidth, int nHeight, uint uFlags);

        public const UInt32 SWP_NOSIZE = 0x0001;
        public const UInt32 SWP_NOMOVE = 0x0002;
        public const UInt32 SWP_NOZORDER = 0x0004;
        public const UInt32 SWP_NOREDRAW = 0x0008;
        public const UInt32 SWP_NOACTIVATE = 0x0010;
        public const UInt32 SWP_FRAMECHANGED = 0x0020;  /* The frame changed: send WM_NCCALCSIZE */
        public const UInt32 SWP_SHOWWINDOW = 0x0040;
        public const UInt32 SWP_HIDEWINDOW = 0x0080;
        public const UInt32 SWP_NOCOPYBITS = 0x0100;
        public const UInt32 SWP_NOOWNERZORDER = 0x0200;  /* Don't do owner Z ordering */
        public const UInt32 SWP_NOSENDCHANGING = 0x0400;  /* Don't send WM_WINDOWPOSCHANGING */


        [return: MarshalAs(UnmanagedType.Bool)]
        [DllImport("User32.dll")]
        internal static extern bool SetCursorPos(int X, int Y);

        [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
        static extern bool GetCursorPos([In, Out] POINT pt);

        public static POINT GetCursorPosition()
        {
            POINT result = new POINT();
            GetCursorPos(result);
            return result;
        }
    }
}

// Wrapper.Windows